'use strict';

const fs = require('fs');
const path = require('path');
const { EventEmitter } = require('events');
const RpcClient = require('./rpcClient');

/**
 * RPC代理，支持按需连接，懒加载模式
 * 提供RPC[serviceName][method](port, ...params) 访问方式
 */
class RpcProxy extends EventEmitter {
  /**
   * 构造函数
   */
  constructor() {
    super();
    // 服务配置缓存 {serviceName: {name, ports, host, global}}
    this._serviceConfigs = new Map();

    // 客户端实例缓存 {serviceName:port: RpcClient}
    this._clientCache = new Map();

    // 代理处理器
    this._handler = null;

    // 是否为调试模式
    this._isDebug = process.env.NODE_ENV !== 'production';

    // 配置目录
    this._configDir = path.resolve(process.cwd(), 'config');

    // 初始化代理处理器
    this._initHandler();
  }

  /**
   * 初始化RPC代理
   * @param {Object} options 初始化选项
   * @param {string} options.configDir 配置目录
   * @param {boolean} options.autoConnect 是否自动连接（默认为false，按需连接）
   * @returns {Proxy} RPC代理对象
   */
  async initialize(options = {}) {
    try {
      // 更新配置目录
      if (options.configDir) {
        this._configDir = options.configDir;
      }

      // 加载服务配置
      await this._loadServiceConfigs();

      // 如果配置了自动连接，则预连接所有服务
      if (options.autoConnect === true) {
        console.log('[RpcProxy] 正在预连接所有服务...');
        await this._preConnectAllServices();
      } else {
        console.log('[RpcProxy] 服务将在需要时按需连接');
      }

      // 返回代理对象
      return new Proxy({}, this._handler);
    } catch (error) {
      console.error('[RpcProxy] 初始化RPC代理失败:', error);
      throw error;
    }
  }

  /**
   * 初始化代理处理器
   * @private
   */
  _initHandler() {
    // 一级代理：处理服务名称访问 RPC[serverName]
    this._handler = {
      get: (target, serviceName) => {
        // 如果是Symbol或其他特殊属性，直接返回
        if (typeof serviceName === 'symbol' || serviceName === 'then') {
          return target[serviceName];
        }

        // 返回二级代理，处理管理器名称访问 RPC[serverName][handlerName]
        return new Proxy({}, {
          get: (_, handlerName) => {
            // 如果是Symbol或其他特殊属性，直接返回
            if (typeof handlerName === 'symbol' || handlerName === 'then') {
              return undefined;
            }

            // 返回三级代理，处理方法名访问 RPC[serverName][handlerName][methodName]
            return new Proxy({}, {
              get: (__, methodName) => {
                // 如果是Symbol或其他特殊属性，直接返回
                if (typeof methodName === 'symbol' || methodName === 'then') {
                  return undefined;
                }

                // 返回方法调用函数
                return async (port, ...args) => {
                  // 验证端口号
                  const portNumber = parseInt(port, 10);
                  if (isNaN(portNumber)) {
                    throw new Error(`[RpcProxy] 无效的端口号: ${port}`);
                  }

                  // 获取或创建客户端
                  const client = this._getOrCreateClient(serviceName, portNumber);

                  // 构建完整的方法名（handlerName.methodName）
                  const fullMethodName = `${handlerName}.${methodName}`;

                  // 调用远程方法
                  return client[fullMethodName](...args);
                };
              }
            });
          }
        });
      }
    };
  }

  /**
   * 获取或创建客户端
   * @param {string} serviceName 服务名称
   * @param {string} handler 处理器名称
   * @param {number} port 端口号
   * @returns {Object} 客户端代理对象
   * @private
   */
  _getOrCreateClient(serviceName, port) {
    const cacheKey = `${serviceName}:${port}`;

    // 检查缓存中是否存在该服务实例的客户端
    if (this._clientCache.has(cacheKey)) {
      return this._clientCache.get(cacheKey);
    }

    // 获取服务配置
    const serviceConfig = this._serviceConfigs.get(serviceName);
    const host = (serviceConfig && serviceConfig.host) || 'localhost';

    // 创建新的RPC客户端（延迟连接）
    const client = new RpcClient(serviceName, port, host);

    // 缓存客户端
    this._clientCache.set(cacheKey, client);

    // 注册到服务配置(如果不存在)
    if (!serviceConfig) {
      this._serviceConfigs.set(serviceName, {
        name: serviceName,
        ports: [port],
        host: host,
        global: false
      });
    } else if (!serviceConfig.ports.includes(port)) {
      serviceConfig.ports.push(port);
    }

    if (this._isDebug) {
      console.log(`[RpcProxy] 已创建服务客户端: ${serviceName}:${port} (延迟连接)`);
    }

    return client;
  }

  /**
   * 加载服务配置
   * @private
   */
  async _loadServiceConfigs() {
    try {
      const serverConfigPath = path.join(this._configDir, 'server.json');

      if (!fs.existsSync(serverConfigPath)) {
        console.warn(`[RpcProxy] 服务配置文件不存在: ${serverConfigPath}`);
        return;
      }

      const serverConfigContent = fs.readFileSync(serverConfigPath, 'utf8');
      const serverConfig = JSON.parse(serverConfigContent);

      // 处理服务进程配置
      if (serverConfig.processes && Array.isArray(serverConfig.processes)) {
        for (const processConfig of serverConfig.processes) {
          // 跳过当前服务
          if (processConfig.name === process.env.SERVICE_NAME) {
            continue;
          }

          // 计算端口列表
          const ports = [];
          for (let i = 0; i < (processConfig.number || 1); i++) {
            ports.push(processConfig.port + i);
          }

          // 保存服务配置
          this._serviceConfigs.set(processConfig.name, {
            name: processConfig.name,
            type: processConfig.type,
            host: processConfig.host || 'localhost',
            ports: ports,
            global: processConfig.global === 1
          });

          if (this._isDebug) {
            console.log(`[RpcProxy] 已加载服务配置: ${processConfig.name}, 端口: [${ports.join(', ')}]`);
          }
        }
      } else {
        console.warn(`[RpcProxy] 服务配置文件格式错误: ${serverConfigPath}`);
      }
    } catch (error) {
      console.error('[RpcProxy] 加载服务配置失败:', error);
      throw error;
    }
  }

  /**
   * 预连接所有服务
   * @private
   */
  async _preConnectAllServices() {
    const connectPromises = [];

    for (const [serviceName, serviceConfig] of this._serviceConfigs.entries()) {
      for (const port of serviceConfig.ports) {
        const client = this._getOrCreateClient(serviceName, port);

        // 尝试连接
        const connectPromise = client.connect()
          .catch(err => {
            console.warn(`[RpcProxy] 预连接 ${serviceName}:${port} 失败: ${err.message}`);
          });

        connectPromises.push(connectPromise);
      }
    }

    // 等待所有连接尝试完成
    if (connectPromises.length > 0) {
      await Promise.allSettled(connectPromises);
    }
  }

  /**
   * 注册服务实例
   * @param {string} serviceName 服务名称
   * @param {number} port 端口号
   */
  registerInstance(serviceName, port) {
    // 添加到服务配置，但不立即连接
    if (!this._serviceConfigs.has(serviceName)) {
      this._serviceConfigs.set(serviceName, {
        name: serviceName,
        ports: [port],
        host: 'localhost',
        global: false
      });
    } else {
      const config = this._serviceConfigs.get(serviceName);
      if (!config.ports.includes(port)) {
        config.ports.push(port);
      }
    }

    console.log(`[RpcProxy] 已注册服务实例 ${serviceName}:${port} (延迟连接)`);
    this.emit('instance-registered', { serviceName, port });
  }

  /**
   * 移除服务实例
   * @param {string} serviceName 服务名称
   * @param {number} port 端口号
   */
  removeInstance(serviceName, port) {
    const cacheKey = `${serviceName}:${port}`;

    // 断开客户端连接
    if (this._clientCache.has(cacheKey)) {
      const client = this._clientCache.get(cacheKey);
      client.disconnect();
      this._clientCache.delete(cacheKey);
    }

    // 从配置中移除
    if (this._serviceConfigs.has(serviceName)) {
      const config = this._serviceConfigs.get(serviceName);
      config.ports = config.ports.filter(p => p !== port);
    }

    console.log(`[RpcProxy] 已移除服务实例 ${serviceName}:${port}`);
    this.emit('instance-removed', { serviceName, port });
  }

  /**
   * 检查服务实例是否已连接
   * @param {string} serviceName 服务名称
   * @param {number} port 端口号
   * @returns {boolean} 是否已连接
   */
  isConnected(serviceName, port) {
    const cacheKey = `${serviceName}:${port}`;

    if (this._clientCache.has(cacheKey)) {
      const client = this._clientCache.get(cacheKey);
      return client.isConnected();
    }

    return false;
  }

  /**
   * 断开所有连接
   */
  disconnectAll() {
    for (const client of this._clientCache.values()) {
      client.disconnect();
    }

    // 清空缓存
    this._clientCache.clear();

    console.log('[RpcProxy] 已断开所有连接');
    this.emit('all-disconnected');
  }
}

module.exports = new RpcProxy(); 